# conftest.py
import pytest
from selenium import webdriver
import logging
from time import sleep
from allure_commons.types import AttachmentType
import allure
from db_utils import DBUtils

# --------------------- 配置部分 ---------------------
# 数据库配置
DB_CONFIG = {
    'host': 'localhost',
    'port': 3306,
    'user': 'root',
    'password': '',
    'database': 'test_db'
}

# 测试用户数据
TEST_USER = {
    'username': '20171111111',
    'password': '111111',
    'name': '李四'
}

# 浏览器配置
BROWSER_CONFIG = {
    'headless': False,  # 是否无头模式
    'window_size': (1920, 1080),  # 浏览器窗口大小
    'implicit_wait': 10  # 隐式等待时间(秒)
}

# --------------------- 日志配置 ---------------------
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("test.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

# --------------------- Allure报告集成 ---------------------
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    """
    钩子函数，用于向Allure报告添加额外信息
    当测试失败时自动截图并保存页面源码
    """
    outcome = yield
    rep = outcome.get_result()
    
    # 只在测试执行阶段且失败时触发
    if rep.when == 'call' and rep.failed:
        driver_fixture = item.funcargs.get('driver')
        if driver_fixture is not None:
            try:
                # 添加截图到报告
                allure.attach(
                    driver_fixture.get_screenshot_as_png(),
                    name='failure_screenshot',
                    attachment_type=AttachmentType.PNG
                )
                # 添加页面源码到报告
                allure.attach(
                    driver_fixture.page_source,
                    name='failure_page_source',
                    attachment_type=AttachmentType.HTML
                )
                # 添加浏览器日志到报告
                if hasattr(driver_fixture, 'get_log'):
                    try:
                        browser_logs = driver_fixture.get_log('browser')
                        if browser_logs:
                            allure.attach(
                                str(browser_logs),
                                name='browser_logs',
                                attachment_type=AttachmentType.TEXT
                            )
                    except Exception as log_error:
                        logger.warning(f"无法获取浏览器日志: {log_error}")
            except Exception as e:
                logger.error(f"无法附加失败信息到Allure报告: {e}")

# --------------------- 测试夹具(fixtures) ---------------------
@pytest.fixture(scope="session")
def db_utils():
    """全局数据库工具实例"""
    logger.info("初始化数据库连接...")
    utils = DBUtils(**DB_CONFIG)
    yield utils
    logger.info("关闭数据库连接...")
    # 这里不需要手动关闭，因为DBUtils使用了contextmanager

@pytest.fixture(scope="module")
def driver():
    """浏览器驱动实例"""
    logger.info("初始化浏览器驱动...")
    
    # 创建Chrome选项
    options = webdriver.ChromeOptions()
    if BROWSER_CONFIG['headless']:
        options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-dev-shm-usage')
    
    # 初始化浏览器驱动
    try:
        driver = webdriver.Chrome(options=options)
        driver.implicitly_wait(BROWSER_CONFIG['implicit_wait'])
        driver.set_window_size(*BROWSER_CONFIG['window_size'])
        
        logger.info("访问首页...")
        driver.get('http://localhost:8000/')
        
        yield driver
        
    except Exception as e:
        logger.error(f"浏览器初始化失败: {e}")
        raise
    finally:
        logger.info("关闭浏览器...")
        driver.quit()

@pytest.fixture(scope="module")
def setup_test_data(db_utils):
    """测试数据准备"""
    logger.info("开始准备测试数据...")
    
    # 清理可能存在的测试用户
    if db_utils.check_user_exists(TEST_USER['username']):
        logger.info(f"清理已存在的测试用户: {TEST_USER['username']}")
        db_utils.delete_user(TEST_USER['username'])
    
    # 创建测试用户
    logger.info(f"创建测试用户: {TEST_USER}")
    db_utils.create_test_user(
        username=TEST_USER['username'],
        password=TEST_USER['password'],
        name=TEST_USER['name']
    )
    
    yield  # 测试执行
    
    # 测试结束后清理数据(可选)
    # logger.info("清理测试数据...")
    # db_utils.delete_user(TEST_USER['username'])

@pytest.fixture
def reset_page(driver):
    """重置页面状态"""
    with allure.step("重置页面到初始状态"):
        logger.info("重置页面到首页...")
        driver.get('http://localhost:8000/')
        sleep(1)  # 等待页面加载

# --------------------- Allure环境配置 ---------------------
def pytest_sessionstart(session):
    """测试会话开始时执行"""
    # 创建Allure环境文件
    import os
    if not os.path.exists('allure-results'):
        os.makedirs('allure-results')
    
    # 写入环境信息
    with open('allure-results/environment.properties', 'w') as f:
        f.write(f"Browser=Chrome\n")
        f.write(f"Browser.Headless={BROWSER_CONFIG['headless']}\n")
        f.write(f"Browser.Window.Size={BROWSER_CONFIG['window_size'][0]}x{BROWSER_CONFIG['window_size'][1]}\n")
        f.write(f"Base.URL=http://localhost:8000\n")
        f.write(f"Database.Host={DB_CONFIG['host']}\n")
        f.write(f"Database.Name={DB_CONFIG['database']}\n")

@pytest.fixture(scope="function")
def allure_environment(request, driver):
    """为每个测试函数提供Allure环境步骤"""
    test_name = request.node.name
    with allure.step(f"准备测试环境: {test_name}"):
        # 可以在这里添加更多的环境准备步骤
        pass
    
    yield
    
    with allure.step(f"清理测试环境: {test_name}"):
        # 可以在这里添加环境清理步骤
        pass